#include "gkt_debug.h"
#include "gkt_screen.h"
#include "gkt_font.h"
#include "font_internal.h"

#if GKT_FONT_ENABLE

/*
 * example:
 * 	#define GKT_CONFIG_FONT_LIB_TABLE	\
 *		GKT_FONT_LIB(ascii, song, 14)	\
 *		GKT_FONT_LIB(gb2312, song, 14)	\
 *		GKT_FONT_LIB(ascii, song, 24)
 */
#define GKT_FONT_LIB_NAME(code_type, typeface, font_size)	\
	gc_font_##code_type##_##typeface##_##font_size

/* declare font lib */
#undef GKT_FONT_LIB
#define GKT_FONT_LIB(code_type, typeface, font_size)	\
	extern const font_lib_s GKT_FONT_LIB_NAME(code_type, typeface, font_size);
GKT_CONFIG_FONT_LIB_TABLE

/* define font lib table */
#undef GKT_FONT_LIB
#define GKT_FONT_LIB(code_type, typeface, font_size)	\
	& GKT_FONT_LIB_NAME(code_type, typeface, font_size),
static const font_lib_s *sc_font_libs[] = {
	GKT_CONFIG_FONT_LIB_TABLE
};

static const font_lib_s *font_find_lib(uint32_t code_type,
					uint32_t font_size)
{
	uint32_t font_libs_num = sizeof(sc_font_libs) / sizeof(font_lib_s *);
	uint32_t i;

	for (i = 0; i < font_libs_num; i++) {
		if (sc_font_libs[i]
			&& (code_type == sc_font_libs[i]->code_type) 
			&& ((font_size == sc_font_libs[i]->size) || !font_size))
		{
			return sc_font_libs[i];
		}
	}

	return NULL;
}

static uint32_t font_find_index(const font_lib_s *font, 
						font_code_t code)
{
	uint32_t head, midd, tail;

	if ((code >= font->codes[0]) 
		&& (code <= font->codes[font->count - 1]))
	{
		head = midd = 0;
		tail = (uint32_t)font->count - 1;		
		do {
			midd = (head + tail) >> 1;
			if (font->codes[midd] == code)
				return midd;
			else if (font->codes[midd] < code)
				head = midd + 1;
			else
				tail = midd - 1;
		} while (head <= tail);
	}

	gkt_info("font: no matched, code = 0x%x\n", code);

	/* if no match code, return the first font matrix index(0) */
	return 0;
}

uint32_t gkt_font_get_width(uint32_t code_type,
					uint32_t font_size)
{
	const font_lib_s *font;
	uint32_t width = 0;

	if (code_type < GKT_FONT_CODE_MAX) {
		font = font_find_lib(code_type, font_size);
		if (font)
			width = font->width;
	}

	return width;
}

uint32_t gkt_font_draw_text(
				const char *text, gkt_rect_s *rect, 
				gkt_font_draw_params_s *params)
{
	const font_lib_s *font_lib_table[GKT_FONT_CODE_MAX];
	const font_lib_s *font;
	const uint8_t *font_data;
	gkt_rect_s ch_rect;
	uint32_t offset, index;
	font_code_t code;
	uint8_t ch;

	for (index = 0; index < GKT_FONT_CODE_MAX; index++)
		font_lib_table[index] = font_find_lib(index, params->size);

	ch_rect.x = rect->x;
	ch_rect.y = rect->y;
	ch_rect.height = gkt_min((uint16_t)params->size, rect->height);

	offset = 0;
	code = 0;
	while ((ch = (uint8_t)text[offset++]) != 0) {
		code = (code << 8) | (font_code_t)ch;
		if ((code >= FONT_ASCII_START) 
			&& (code <= FONT_ASCII_END))
		{
			font = font_lib_table[GKT_FONT_CODE_ASCII];
		}
		else if ((code >= FONT_GB2312_START) 
			&& (code <= FONT_GB2312_END))
		{
			font = font_lib_table[GKT_FONT_CODE_GB2312];
		}
		else {
			if ((code < 0xA1) || (code > 0xFE)) {	/* not High Byte of GB2312 */
				gkt_trace("font_draw_text: unrecognised code - 0x%02x\n", code);
				code = 0;
			}
			continue;
		}

		if (font) {
			index = font_find_index(font, code);
			font_data = font->data + (font->bytes * index);
			ch_rect.width = font->width;
			if ((ch_rect.x + ch_rect.width) <= (rect->x + rect->width)) {
				gkt_screen_draw_bitmap(font_data, &ch_rect, 
						params->fg_color, params->bg_color, 
						params->update);
				ch_rect.x += font->width + params->x_space;
			}
			else {
				gkt_trace("font_draw_text: out-of-rectange!\n");
				break;
			}
		}

		code = 0;
	}

	return (ch_rect.x - rect->x);
}

void gkt_font_get_text_info(
				const char *text, uint32_t font_size,
				gkt_font_text_info_s *text_info)
{
	const font_lib_s *font_lib_table[GKT_FONT_CODE_MAX];
	const font_lib_s *font;
	uint32_t offset, code_type, character_nums;
	font_code_t code;
	uint8_t ch;

	for (code_type = 0; code_type < GKT_FONT_CODE_MAX; code_type++)
		font_lib_table[code_type] = font_find_lib(code_type, font_size);

	text_info->total_width = 0;

	character_nums = 0;
	offset = 0;
	code = 0;
	while ((character_nums < text_info->character_nums) 
		&& ((ch = (uint8_t)text[offset++]) != 0)) 
	{
		code = (code << 8) | (font_code_t)ch;
		if ((code >= FONT_ASCII_START) 
			&& (code <= FONT_ASCII_END))
		{
			font = font_lib_table[GKT_FONT_CODE_ASCII];
		}
		else if ((code >= FONT_GB2312_START) 
			&& (code <= FONT_GB2312_END))
		{
			font = font_lib_table[GKT_FONT_CODE_GB2312];
		}
		else {
			if ((code < 0xA1) || (code > 0xFE)) {	/* not High Byte of GB2312 */
				gkt_trace("font_text_info: unrecognised code - 0x%02x\n", code);
				code = 0;
			}
			continue;
		}

		if (font) {
			character_nums++;
			text_info->total_width += (uint32_t)font->width;
		}
	
		code = 0;
	}

	text_info->character_nums = character_nums;
}

#endif

